#pragma once

#include <iostream>

using namespace std;

enum Color
{
	RED,
	BLACK
};

template<class T>
struct RBNode
{
	T _val;
	RBNode<T>* _left;
	RBNode<T>* _right;
	RBNode<T>* _parent;
	Color _col;

	RBNode(const T& val)
		: _val(val)
		, _left(nullptr)
		, _right(nullptr)
		, _parent(nullptr)
	{

	}

};

template<class T,class Ref,class Ptr>
struct RBTreeIterator
{
	typedef RBNode<T> Node;
	typedef RBTreeIterator<T, Ref, Ptr> Self;

	Node* _node;
	Node* _root;

	RBTreeIterator(Node* node,Node* root)
		:_node(node)
		,_root(root)
	{

	}

	Ref operator*()
	{
		return _node->_val;
	}

	Ptr operator->()
	{
		return &_node->_val;
	}

	bool operator==(const Self& rbt)const 
	{
		return rbt._node == _node;
	}

	bool operator!=(const Self& rbt)const 
	{
		return rbt._node != _node;
	}

	Self& operator++()
	{
		if (_node->_right)
		{
			Node* mostleft = _node->_right;
			while (mostleft->_left)
			{
				mostleft = mostleft->_left;
			}

			_node = mostleft;
		}
		else
		{
			Node* cur = _node;
			Node* parent = cur->_parent;

			while (parent && parent->_right == cur)
			{
				cur = parent;
				parent = parent->_parent;
			}

			_node = parent;
		}

		return *this;
	}

	Self& operator--()
	{
		if (_node == nullptr)
		{
			Node* mostright = _root->_right;
			while (mostright->_right)
			{
				mostright = mostright->_right;
			}
			_node = mostright;
		}
		else if (_node->_left)
		{
			Node* mostrt = _node->_left;
			while (mostrt->_right)
			{
				mostrt = mostrt->_right;
			}

			_node = mostrt;
		}
		else
		{
			Node* cur = _node;
			Node* parent = cur->_parent;

			while (parent && parent->_left == cur)
			{
				cur = parent;
				parent = parent->_parent;
			}

			_node = parent;
		}

		return *this;
	}
};

template<class K,class T,class KeyOfT>
class RBTree
{
	typedef RBNode<T> Node;
public:
	typedef RBTreeIterator<T, T&, T*> Iterator;
	typedef RBTreeIterator<T, const T&, const T*> ConstIterator;

	RBTree() = default;

	~RBTree()
	{
		Destroy(_root);
		_root = nullptr;
	}

	void Destroy(Node* root)
	{
		if (root == nullptr)
		{
			return;
		}

		Destroy(root->_left);
		Destroy(root->_right);

		delete root;
	}

	Iterator Begin()
	{
		Node* mostleft = _root;

		while (mostleft&&mostleft->_left)
		{
			mostleft = mostleft->_left;
		}

		return Iterator(mostleft, _root);
	}

	Iterator End()
	{
		return Iterator(nullptr, _root);
	}

	ConstIterator Begin()const 
	{
		Node* mostleft = _root;

		while (mostleft && mostleft->_left)
		{
			mostleft = mostleft->_left;
		}

		return ConstIterator(mostleft, _root);
	}

	ConstIterator End()const
	{
		return ConstIterator(nullptr, _root);
	}

	pair<Iterator,bool> Insert(const T& val)
	{
		if (_root == nullptr)
		{
			_root = new Node(val);
			_root->_col = BLACK;
			return pair<Iterator, bool>{Iterator(_root, _root), true};
		}

		Node* parent = nullptr;
		Node* cur = _root;
		KeyOfT kot;

		while (cur)
		{
			if (kot(cur->_val) > kot(val))
			{
				parent = cur;
				cur = cur->_left;
			}
			else if (kot(cur->_val) < kot(val))
			{
				parent = cur;
				cur = cur->_right;
			}
			else
			{
				return pair<Iterator, bool>{Iterator(cur, _root), false};
			}
		}

		cur = new Node(val);
		Node* newnode = cur;
		cur->_col = RED;

		if (kot(parent->_val) > kot(val))
		{
			parent->_left = cur;
		}
		else
		{
			parent->_right = cur;
		}

		cur->_parent = parent;

		while (parent && parent->_col == RED)
		{
			Node* grandfather = parent->_parent;

			if (grandfather->_left == parent)
			{
				Node* uncle = grandfather->_right;

				if (uncle && uncle->_col == RED)
				{
					parent->_col = uncle->_col = BLACK;
					grandfather->_col = RED;

					cur = grandfather;
					parent = cur->_parent;
				}
				else
				{
					if (parent->_left == cur)
					{
						RotateR(grandfather);

						parent->_col = BLACK;
						grandfather->_col = RED;
					}
					else
					{
						RotateL(parent);
						RotateR(grandfather);

						cur->_col = BLACK;
						grandfather->_col = RED;
					}

					break;
				}
			}
			else
			{
				Node* uncle = grandfather->_left;

				if (uncle && uncle->_col == RED)
				{
					parent->_col = uncle->_col = BLACK;
					grandfather->_col = RED;

					cur = grandfather;
					parent = cur->_parent;
				}
				else
				{
					if (parent->_right == cur)
					{
						RotateL(grandfather);

						parent->_col = BLACK;
						grandfather->_col = RED;
					}
					else
					{
						RotateR(parent);
						RotateL(grandfather);

						cur->_col = BLACK;
						grandfather->_col = RED;
					}

					break;
				}
			}
		}

		_root->_col = BLACK;

		return pair<Iterator, bool>{Iterator(newnode, _root), true};
	}

	void RotateR(Node* parent)
	{
		Node* subL = parent->_left;
		Node* subLR = subL->_right;

		parent->_left = subLR;

		if (subLR)
		{
			subLR->_parent = parent;
		}

		Node* pParent = parent->_parent;

		subL->_right = parent;

		parent->_parent = subL;

		if (pParent == nullptr)
		{
			_root = subL;
			subL->_parent = nullptr;
		}
		else
		{
			if (pParent->_left == parent)
			{
				pParent->_left = subL;
			}
			else
			{
				pParent->_right = subL;
			}
			subL->_parent = pParent;
		}
	}

	void RotateL(Node* parent)
	{
		Node* subR = parent->_right;
		Node* subRL = subR->_left;

		parent->_right = subRL;

		if (subRL)
		{
			subRL->_parent = parent;
		}

		Node* pParent = parent->_parent;

		subR->_left = parent;

		parent->_parent = subR;

		if (pParent == nullptr)
		{
			_root = subR;
			subR->_parent = nullptr;
		}
		else
		{
			if (pParent->_left == parent)
			{
				pParent->_left = subR;
			}
			else
			{
				pParent->_right = subR;
			}
			subR->_parent = pParent;
		}
	}

	Iterator Find(const K& key)
	{
		KeyOfT kot;
		Node* cur = _root;

		while (cur)
		{
			if (kot(cur->_val) > key)
			{
				cur = cur->_left;
			}
			else if (kot(cur->_val) < key)
			{
				cur = cur->_right;
			}
			else
			{
				return Iterator(cur,_root);
			}
		}

		return End();
	}


private:
	Node* _root = nullptr;


};